package com.fingard.dsp.bank.directbank.icbc11.util;


import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import java.io.*;
import java.security.SecureRandom;

/**
 * 文件加/解密测试类
 * @author kfzx-mizr
 * @date 2009-10-23
 * 
 * */
public class FileEncryptionTest {	

	
	/**
	 * 对文件进行加密
	 * 
	 * @param file
	 * @param key 
	 * @throws Exception
	 */
	public static String transformation="DES";
	public static  String enyFile(String filePath, String key) throws Exception {
		File file = new  File(filePath);
		byte[] srcStr = readFile(new FileInputStream(file));		
		byte[] secretkey = hexStringToByte(key);
		
		byte[] enyStr = encrypt(srcStr,
				secretkey, transformation);
		String fileName = file.getAbsolutePath();
		String file_type=".des";
		if ("DESede".equals(transformation))
		{
			file_type=".3des";
		}
		String enyFileName = fileName + file_type;
		
		writeFile(enyFileName, enyStr);
		System.out.println("*--------加密成功--------*\n");
		return enyFileName;
	}

	/**
	 * 对文件进行解密
	 * 
	 * @param fileName
	 * @param key
	 * @throws Exception
	 */
	public static String decFile(String fileName, String key) throws Exception {
		byte[] srcStr = readFile(fileName);
		byte[] secretkey = hexStringToByte(key);		
		byte[] decStr = decrypt(srcStr,
				secretkey, transformation);
		
		String decFileName = fileName.substring(0, fileName.length() - 4);
		if ("DESede".equals(transformation))
		{
			decFileName = fileName.substring(0, fileName.length() - 5);
		}
		
		writeFile(decFileName, decStr);
		System.out.println("*--------解密成功--------*\n");
		return decFileName;
	}
	
	/**
	 * 对明文加密。
	 * 
	 * @param plainText
	 *            要加密的明文。
	 * @param key
	 *            密钥。
	 * @param transformation
	 *            加密算法。
	 * @return 加过密的密文。
	 * @throws Exception
	 *             当加密过程中出现任何错误时。已知的错误有：非法的密钥，未知的加密算法。
	 */
	public static byte[] encrypt(byte[] plainText, byte[] key, String transformation) throws Exception {
		byte[] result = null;

		if ("DES".equals(transformation))
		{
			// 产生一个可信任的随机数源
			SecureRandom sr = new SecureRandom();
			// 从原始密钥数据创建DESKeySpec对象
			DESKeySpec dks = new DESKeySpec(key);
			// 创建一个密钥工厂，然后用它把DESKeySpec转换成Secret Key对象
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey keySpec = keyFactory.generateSecret(dks);
			// Cipher对象实际完成加密操作
			Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
			// 用密钥初始化Cipher对象
			cipher.init(Cipher.ENCRYPT_MODE, keySpec, sr);
			// 执行加密操作
			result = cipher.doFinal(plainText);
		}else if("DESede".equals(transformation))
		{
			// 产生一个可信任的随机数源
			SecureRandom sr = new SecureRandom();
			// 从原始密钥数据创建DESKeySpec对象
			DESedeKeySpec dks = new DESedeKeySpec(key);
			// 创建一个密钥工厂，然后用它把DESKeySpec转换成Secret Key对象
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
			SecretKey keySpec = keyFactory.generateSecret(dks);
			// Cipher对象实际完成加密操作
			Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
			// 用密钥初始化Cipher对象
			cipher.init(Cipher.ENCRYPT_MODE, keySpec, sr);
			// 执行加密操作
			result = cipher.doFinal(plainText);
		}


		return result;
	}

	/**
	 * 对密文解密。
	 * 
	 * @param cryptoText
	 *            要解密的密文。
	 * @param key
	 *            密钥。
	 * @param transformation
	 *            加密算法。
	 * @return 解密的明文。
	 * @throws Exception
	 *             当解密出错时。
	 */
	public static byte[] decrypt(byte[] cryptoText, byte[] key, String transformation) throws Exception {
		byte[] result = null;
			if ("DES".equals(transformation))
			{
				// 产生一个可信任的随机数源
				SecureRandom sr = new SecureRandom();
				// 从原始密钥数据创建DESKeySpec对象
				DESKeySpec dks = new DESKeySpec(key);
				// 创建一个密钥工厂，然后用它把DESKeySpec转换成Secret Key对象
				SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(transformation);
				SecretKey keySpec = keyFactory.generateSecret(dks);
				// Cipher对象实际完成加密操作
				Cipher cipher = Cipher.getInstance(transformation);
				// 用密钥初始化Cipher对象
				cipher.init(Cipher.DECRYPT_MODE, keySpec, sr);
				// 执行解密操作
				result = cipher.doFinal(cryptoText);
			}
			else if("DESede".equals(transformation))
			{
				// 产生一个可信任的随机数源
				SecureRandom sr = new SecureRandom();
				// 从原始密钥数据创建DESKeySpec对象
				DESedeKeySpec dks = new DESedeKeySpec(key);
				// 创建一个密钥工厂，然后用它把DESKeySpec转换成Secret Key对象
				SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
				SecretKey keySpec = keyFactory.generateSecret(dks);
				// Cipher对象实际完成加密操作
				Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
				// 用密钥初始化Cipher对象
				cipher.init(Cipher.DECRYPT_MODE, keySpec, sr);
				// 执行加密操作
				result = cipher.doFinal(cryptoText);
			}

		return result;
	}
	
	
	/************工具类************/
	/**
     * 根据输入文件名，得到文件中的字节
     * @param input
     * @return
     * @throws IOException
     */
	public static byte[] readFile(String input) throws IOException {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(input);
			int count = fis.available();
			System.out.println("文件大小：" + count / 1024 + "K");
			byte[] contents = new byte[count];
			fis.read(contents);
			return contents;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
 		} finally {
			if (fis != null) {
				fis.close();
			}
		}
	}
	

    public static byte[] readFile(InputStream input) throws IOException {
        int length = input.available();
        System.out.println("文件大小：" + length/1024+"K");
        byte[] buffer = new byte[length];
        input.read(buffer, 0, length);
        
        return buffer;
    }
    
	/**
	 * 以字节的形式写文件
	 * @param fileName
	 * @param contents
	 * @throws IOException
	 */
	public static void writeFile(String fileName,byte[] contents) throws IOException{
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(fileName);
			fos.write(contents);
			fos.flush();
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (fos != null) {
				fos.close();
			}
		}
	}
	
	
	 /**
	 * 把16进制字符串转换成字节数组
	 * @param hex
	 * @return
	 */
	 public static byte[] hexStringToByte(String hex) {
		 hex = hex.toUpperCase();
		 int len = (hex.length() / 2);
		 byte[] result = new byte[len];
		 char[] achar = hex.toCharArray();
		 for (int i = 0; i < len; i++) {
		  int pos = i * 2;
		  result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
		 }
		 return result;
	 }
	 
	 private static byte toByte(char c) {
		 byte b = (byte) "0123456789ABCDEF".indexOf(c);
		 return b;
	 }
	
	//测试
	/**
	 * @param args
	 */
	public String exec(String secretKey,String flag,String fileName ) {
		
//		if (args.length != 3)
//        {
//           	System.out.println("使用方法: \njava FileEncryptionTest \"secretKey\" \"flag\" \"fileName\"\n" +
//				"其中，\n" +
//				"secretKey为16为十六进制字符串\n" +
//				"flag为加解密标志，1加密，2解密\n" +
//				"fileName为要加解密的文件\n" +
//				"示例：\n" +
//				"java FileEncryptionTest \"6DF4754A83B919B6\" \"2\" \"E:\\export\\home\\was\\temp\\ENYIAAS80120100705.txt.des\"");
//            System.exit(1);
//        }
//
//		
//		String secretKey = args[0].toUpperCase(); //密钥
//		String flag = args[1]; //加解密标记
//		String fileName = args[2]; //要加解密的文件名称

		//参数校验
		String retmsg;

		if("DES".equals(transformation) && secretKey.length() != 16)
		{
			retmsg="第一个参数secretKey必须为16位十六进制字符串！";
			return retmsg;
		}else if("DESede".equals(transformation) && secretKey.length() != 32  && secretKey.length() != 48)
		{
			retmsg="第一个参数secretKey必须为32或48位十六进制字符串！";
			return retmsg;
		}
		char[] skArray =  secretKey.toCharArray();
		for(int i=0; i<skArray.length; i++)
		{
			if("0123456789ABCDEF".indexOf(skArray[i]) == -1)
			{
				retmsg="第一个参数secretKey必须为16位十六进制字符串！";
				return retmsg;
			}
		}

		if(!"1".equals(flag) && !"2".equals(flag))
		{
				retmsg="第二个参数flag必须为1或者2：1加密，2解密!";
				return retmsg;
		}

		if(!(new File(fileName).exists()))
		{
			retmsg="第三个参数fileName所指路径下的文件不存在!";
			return retmsg;
		}

		//加解密
		if("1".equals(flag))  //加密
		{
			try {	
				String cryptoFileName = FileEncryptionTest.enyFile(fileName, secretKey);		//加密测试	
				retmsg="文件"+fileName+"加解密成功！";
			} catch (Exception e) {
				retmsg="DES加解密失败:\n" + e;;	
				return retmsg;	
				//e.printStackTrace();
			}
		}
		else if("2".equals(flag))  //加密
		{
			try {				
				String plainFileName = FileEncryptionTest.decFile(fileName, secretKey);		//解密测试	
				retmsg="文件"+fileName+"加解密成功！";		
			} catch (Exception e) {
				retmsg="DES加解密失败:\n" + e;;	
				return retmsg;	
				//e.printStackTrace();
			}
		}else
		{
			retmsg="加解密标志错误!" ;	
			return retmsg;	
		}
		return retmsg;

		//For 加密
		/*
		String fileName =  "E:\\export\\home\\was\\temp\\test.txt";		
		try {	
			String cryptoFileName = FileEncryptionTest.enyFile(fileName, secretKey);		//加密测试	
			System.out.println("加密后的文件：" + cryptoFileName);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		*/
		//For 解密
		/*
		String fileName =  "E:\\export\\home\\was\\temp\\ENYIAAS80120100705.txt.des";		
		try {				
			String plainFileName = FileEncryptionTest.decFile(fileName, secretKey);		//解密测试	
			System.out.println("解密后的文件：" + plainFileName);		
		} catch (Exception e) {
			e.printStackTrace();
		}
		*/
	}

}
